#include"download.h"
Download::Download(int index, QSqlDatabase db,QObject *parent)
: QObject(parent), m_Index(index)
{
	m_HaveDoneBytes = 0;
	m_StartPoint = 0;
	m_EndPoint = 0;
	m_File = NULL;
    this->db = db;
}

void Download::StartDownload(const QUrl &url, QFile *file, qint64 startPoint, qint64 middlePoint, qint64 endPoint)
{
    if( NULL == file )
            return;

    m_HaveDoneBytes = 0;
    m_StartPoint = startPoint;
    m_MiddlePoint = middlePoint;
    m_EndPoint = endPoint;
    m_File = file;
    this->url = url;

    //根据HTTP协议，写入RANGE头部，说明请求文件的范围
    QNetworkRequest qheader;
    qheader.setUrl(url);
    QString range;
    range.sprintf("Bytes=%lld-%lld", startPoint, m_EndPoint);
    qheader.setRawHeader("Range", range.toAscii());
    qheader.setRawHeader("Connection","Keep-Alive");
    //开始下载
    qDebug() << "Part " << m_Index << " start download";
    QString sql;
    QSqlQuery query;
    QSqlRecord record;
    sql = "select count(*) from segment where filename ='"+m_File->fileName()+"' and segmentindex = '"+QString::number(m_Index)+"'";
    query = db.exec(sql);
    query.next();
    record = query.record();
    if(record.value(0).toInt() == 0)
    {
        QString segmentinfo = QString::number(m_StartPoint)+"-"+QString::number(m_StartPoint + m_HaveDoneBytes)+"-" + QString::number(m_EndPoint);
          sql  = "insert into segment(filename,segmentinfo,url,segmentindex) values ('"+m_File->fileName()+"','"+segmentinfo+"','"+url.toString()+"','"
          +QString::number(m_Index)+"')";
          qDebug()<<sql;
          query = db.exec(sql);
          qDebug()<<"StartDownload:"<<query.lastError().text();
    }
    m_Reply = m_Qnam.get(QNetworkRequest(qheader));
    connect(m_Reply, SIGNAL(finished()),
            this, SLOT(FinishedSlot()));
    connect(m_Reply, SIGNAL(readyRead()),
            this, SLOT(HttpReadyRead()));
}

void Download::StartDownload(const QUrl &url, 
								 QFile *file,
								 qint64 startPoint/* =0 */,
								 qint64 endPoint/* =-1 */)
{
	if( NULL == file )
		return;

	m_HaveDoneBytes = 0;
	m_StartPoint = startPoint;
	m_EndPoint = endPoint;
	m_File = file;
	//根据HTTP协议，写入RANGE头部，说明请求文件的范围
	QNetworkRequest qheader;
	qheader.setUrl(url);
	QString range;
	range.sprintf("Bytes=%lld-%lld", m_StartPoint, m_EndPoint);
	qheader.setRawHeader("Range", range.toAscii());
    qheader.setRawHeader("Connection","Keep-Alive");
	//开始下载
	qDebug() << "Part " << m_Index << " start download";
	m_Reply = m_Qnam.get(QNetworkRequest(qheader));
	connect(m_Reply, SIGNAL(finished()),
		this, SLOT(FinishedSlot()));
	connect(m_Reply, SIGNAL(readyRead()),
		this, SLOT(HttpReadyRead()));
}

void Download::StopDownload(void)
{
    disconnect(m_Reply, SIGNAL(readyRead()),
               this, SLOT(HttpReadyRead()));
    disconnect(m_Reply, SIGNAL(finished()),
                    this, SLOT(FinishedSlot()));
    m_Reply->deleteLater();
    m_Reply = 0;
}

//下载结束
void Download::FinishedSlot()
{

	qDebug() << "Part " << m_Index << " download finished";
        m_File->flush();
        m_Reply->deleteLater();
        m_Reply = 0;
        m_File = 0;
	emit DownloadFinished();
}

void Download::HttpReadyRead()
{
	if ( !m_File )
		return;
	//将读到的信息写入文件
        QByteArray buffer = m_Reply->readAll();
        m_File->seek(m_StartPoint + m_HaveDoneBytes );
        m_File->write(buffer);
        m_File->flush();

        m_HaveDoneBytes += buffer.size();
        QString segmentinfo = QString::number(m_StartPoint)+"-"+QString::number(m_StartPoint+m_MiddlePoint+m_HaveDoneBytes)+"-" + QString::number(m_EndPoint);
        QString sql ="update segment set segmentinfo ='"+segmentinfo +"' where filename ='"+m_File->fileName() +"' and segmentindex='"+QString::number(m_Index)+"'";
        qDebug()<<"HttpReadyRead"<<sql;
        QSqlQuery query = db.exec(sql);
        qDebug()<<"HttpReadRead"<<query.lastError().text();
        emit SendWriteData(buffer.size());
}
//========================================================================================================================
//用阻塞的方式获取下载文件的长度
qint64 DownloadControl::GetFileSize(QUrl url)
{
	QNetworkAccessManager manager;
	qDebug() << "Getting the file size...";
	QEventLoop loop;
	//发出请求，获取目标地址的头部信息
	QNetworkReply *reply = manager.head(QNetworkRequest(url));
	QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()), Qt::DirectConnection);
	loop.exec();
	QVariant var = reply->header(QNetworkRequest::ContentLengthHeader);
	delete reply;
	qint64 size = var.toLongLong();
	qDebug() << "The file size is: " << size;
	return size;
}

void DownloadControl::CounterRate(qint64 data)
{
    m_DataSize += data;
    qDebug()<<"m_DataSize:"<<m_DataSize;
    rate = m_DataSize/1024/(float(m_Time->elapsed())/1000);
    int percent = int((m_DataSize/float(m_FileSize))*100);
    QFileInfo fileInfo(m_File->fileName());
    QString sql = "update downloadfileinfo  set finishsize ='"+ QString::number(m_DataSize) +"' where  filename = '"+m_File->fileName()+"'";
    db.exec(sql);
    emit DownloadInfo(fileInfo.fileName(),rate,percent,m_Path);
}

void DownloadControl::SetSavePath(const QString &path)
{
    m_Path = path;
}

void DownloadControl:: GetFileSizeAndFileName(QUrl url,QUrl& newurl,int &size,QString &filename)
{
        /*
           发送http;
           分析http头文件
           如果有size ,就分析文件名
           Content-Disposition: attachment; filename=ttpsetup-44059078.exe
           Content-Disposition: attachment; filename="ttpsetup-44059078.exe"
           如果没有size，就去拿location
           如果既没有size，也没有location ，就停止下载
         */
        QNetworkAccessManager manager;
        qDebug()<<"get  http infomation";
        QEventLoop loop;
        QNetworkReply *reply = manager.head(QNetworkRequest(url));
        qDebug()<<"url:"<<url;
        QObject::connect(reply,SIGNAL(finished()),&loop,SLOT(quit()),Qt::DirectConnection);
        loop.exec();
        int code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
        qDebug()<<"http code:"<<code;
        if (code == 200)
        {
            QVariant varcontentlength = reply->header(QNetworkRequest::ContentLengthHeader);
            size = varcontentlength.toLongLong();
            qDebug()<<"file size:"<<size;
            QByteArray  bytecontentdisposition = reply->rawHeader(QByteArray("Content-Disposition"));
            if ( bytecontentdisposition.isNull() == false)
            {
                qDebug()<<"Content-Disposition:"<<bytecontentdisposition;
                if (bytecontentdisposition[0] == '"' || bytecontentdisposition[0] == '\'')
                {
                        bytecontentdisposition = bytecontentdisposition.mid(1,(bytecontentdisposition.size()-2));
                }
                QList<QByteArray> dispositionlist = bytecontentdisposition.split('=');
                qDebug()<<"filename length"<<dispositionlist[1].size();
                if(dispositionlist[1][0] == '"' || dispositionlist[1][0] == '\'')
                    filename = dispositionlist[1].mid(1,(dispositionlist[1].size()-2));
                else
                    filename = dispositionlist[1];
                qDebug()<<"filename"<<filename;
            }
            else
            {
                QFileInfo fileInfo(url.path());
                filename = fileInfo.fileName();
            }
            newurl = url;
            return ;
        }
        else if (code == 302)
        {
            QVariant varlocation = reply->header(QNetworkRequest::LocationHeader);
            QString location = varlocation.toString();
            qDebug()<<"location:"<<location;
            GetFileSizeAndFileName(QUrl(location),newurl,size,filename);
        }
        else
        {
               //停止下载
                size = 0;
                filename = QString::null;
                return;
        }
}

DownloadControl::DownloadControl(QObject *parent)
: QObject(parent)
{
        m_DownloadCount = 0;
        m_FinishedNum = 0;
        m_FileSize = 0;
        m_File = new QFile;
        m_DataSize = 0;
        m_Time = NULL;
}

void DownloadControl::Init(const QString &url, int count)
{
        this->strUrl = url;
        this->m_DownloadCount = count;
}

void DownloadControl::run(void)
{
        this->StartFileDownload(this->strUrl,this->m_DownloadCount);
}

void DownloadControl::StopDownload(const QString &filename)
{
        for(int i =0;i<downlist.size();i++)
        {
            downlist.at(i)->StopDownload();
            qDebug()<<"StopDownload ........................................................................";
        }
        m_File->flush();
        m_File->close();
        delete m_Time;
        m_Time = NULL;
        downlist.clear();
}

void DownloadControl::ContinueDownload(const QString &filename)
{
    m_FinishedNum = 0;
    db = QSqlDatabase::addDatabase("QSQLITE","downloadcontrol");
    db.setDatabaseName("./database");
    db.open();
    if(!m_File->isOpen())
    {
        m_File->setFileName(filename);
        m_File->open(QIODevice::ReadWrite);
    }
    if(m_Time == NULL)
        m_Time = new QTime();
    QString sql = "select * from downloadfileinfo where filename = '"+filename+"'";
    QSqlQuery query = db.exec(sql);
    qDebug()<<query.lastError().text();
    query.next();
    QSqlRecord record = db.record("downloadfileinfo");
    m_DownloadCount = query.value(record.indexOf("pointinfo")).toInt();
    sql = "select * from segment where filename = '"+ filename +"' order by segmentindex ASC";
    query = db.exec(sql);
    record = db.record("segment");
    m_Time->start();
    while(query.next())
    {
        //QThread::usleep(100);
        QString segmentinfo = query.value(record.indexOf("segmentinfo")).toString();
        QStringList segmentlist = segmentinfo.split("-");
        int index = query.value(record.indexOf("segmentindex")).toInt();
        qDebug()<<"index";
        Download* tempDownload = new Download(index,db, this);
        downlist.append(tempDownload);
        //qDebug()<<segmentlist[0].toInt()<<"    "<<segmentlist[1].toInt()<<" "<<segmentlist[2].toInt();
        connect(tempDownload, SIGNAL(DownloadFinished()),
                this, SLOT(SubPartFinished()));
        connect(tempDownload, SIGNAL(DownloadFinished()),
                tempDownload, SLOT(deleteLater()));
        connect(tempDownload,SIGNAL(SendWriteData(qint64)),
                this,SLOT(CounterRate(qint64)));
        tempDownload->StartDownload(m_Url, m_File, segmentlist[1].toInt(),0, segmentlist[2].toInt());
    }

}

void DownloadControl::setDataBase(const QSqlDatabase &db)
{
        this->db = db;
}

void DownloadControl::StartFileDownload(const QString &url, int count)
{
        if(m_Time == NULL)
            m_Time = new QTime();
        db = QSqlDatabase::addDatabase("QSQLITE","downloadcontrol");
        db.setDatabaseName("./database");
        db.open();
        m_DownloadCount = count;
        m_FinishedNum = 0;
        QString fileName;
        QUrl newurl,qurl;
        qurl.setEncodedUrl(url.toUtf8());
        GetFileSizeAndFileName(qurl,newurl,m_FileSize,fileName);
        m_Url = newurl;
        qDebug()<<"open file name:"<<fileName;
        if(m_Path.at(m_Path.size()-1).toAscii() =='/')
            m_File->setFileName(m_Path+fileName);
        else
            m_File->setFileName(m_Path + QString("/") + fileName);
        m_File->open(QIODevice::ReadWrite);
        Download *tempDownload;
        //isfinish 0 表示没有完成，1表示完成
        QString sql;
        sql ="select count(*) from downloadfileinfo where filename ='"+m_File->fileName()+"' and isfinish = '0'";
        QSqlQuery query = db.exec(sql);
        query.next();
        QSqlRecord record = query.record();
        if(record.value(0).toInt()!=0)
        {
            QMessageBox prompt;
            prompt.setText("文件已经在下载列表中，请继续下载原文件");
            prompt.exec();
            sql = "select * from downloadfileinfo where filename ='"+m_File->fileName()+"' and isfinish = '0'";
            QSqlQuery query = db.exec(sql);
            query.next();
            QSqlRecord record = db.record("downloadfileinfo");
            m_DownloadCount = query.value(record.indexOf("pointinfo")).toInt();
            m_DataSize = query.value(record.indexOf("finishsize")).toInt();
            m_File->close();
            db.close();
            QSqlDatabase::removeDatabase("downloadcontrol");
            return ;
        }
        else
        {
            sql = "insert into downloadfileinfo (url,filename,filesize,finishsize,pointinfo,isfinish) values('"+m_Url.toString()+"','"+m_File->fileName()+"','"
                          +QString::number(m_FileSize)+"','0','"+QString::number(m_DownloadCount)+"','0')";
            qDebug()<<sql;
            //execsql(sql);
            db.exec(sql);
            emit ChangeTodayTable();
        }
	//将文件分成PointCount段，用异步的方式下载
        m_Time->start();
        //文件大小 ，段数，url，文件名
        for(int i=0; i<m_DownloadCount; i++)
        {
            //先算出每段的开头和结尾（HTTP协议所需要的信息）
            int start = m_FileSize * i / m_DownloadCount;
                    qDebug()<<"m_FileSize"<<m_FileSize <<"start:"<<start;
            int end = m_FileSize * (i+1) / m_DownloadCount;
                    if(end >= m_FileSize)
                        end =m_FileSize;

		//分段下载该文件
            tempDownload = new Download(i+1,db, this);
            downlist.append(tempDownload);
            connect(tempDownload, SIGNAL(DownloadFinished()),
			this, SLOT(SubPartFinished()));
            connect(tempDownload, SIGNAL(DownloadFinished()),
			tempDownload, SLOT(deleteLater()));
            connect(tempDownload,SIGNAL(SendWriteData(qint64)),
                        this,SLOT(CounterRate(qint64)));
            tempDownload->StartDownload(m_Url, m_File, start,0, end);
	}
   // exec();
}

void DownloadControl::SubPartFinished()
{
	m_FinishedNum++;
	//如果完成数等于文件段数，则说明文件下载完毕，关闭文件，发生信号
	if( m_FinishedNum == m_DownloadCount )
	{
                QString sql;
                sql ="delete from segment where filename = '"+m_File->fileName()+"'";
                db.exec();
                m_File->close();
                delete m_Time;
                m_Time = NULL;
                db.exec("update downloadfileinfo set isfinish = 1 where filename ='"+m_File->fileName()+"'");
                db.close();
                QSqlDatabase::removeDatabase("downloadcontrol");
                emit FileDownloadFinished();
             //   quit();
                qDebug() << "Download finished";
	}
}

//#include "download.moc"

//int main(int argc, char **argv)
//{
//        QCoreApplication app(argc, argv);
//        //用阻塞的方式下载文件，完成后退出
//        DownloadControl *control = new DownloadControl;
//        QEventLoop loop;
//        QObject::connect(control, SIGNAL(FileDownloadFinished()),
//                &loop, SLOT(quit()));
//        control->StartFileDownload(strUrl, PointCount);
//        loop.exec();
//        return 0;
//}
